﻿using System;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
using System.Threading;
using System.Windows.Forms;

namespace Tsanie.ShellExt
{
    delegate void Action();

    public partial class PluginsForm : Form
    {
        AppDomain managerDomain = null;
        string path = null;

        public PluginsForm()
        {
            InitializeComponent();
        }

        void LoadPlugins()
        {
            buttonAdd.Enabled = false;
            buttonRemove.Enabled = false;
            buttonOK.Enabled = false;
            buttonApply.Enabled = false;
            listProviders.Enabled = false;
            listProviders.Items.Clear();
            try
            {
                // 工作路径
                path = Assembly.GetExecutingAssembly().Location;
                path = path.Substring(0, path.LastIndexOf('\\') + 1);
                openFile.InitialDirectory = path;

                new Thread(delegate()
                {
                    AppDomainSetup ads = new AppDomainSetup();
                    ads.ApplicationName = "Tsanie.Plugins.Manager";
                    ads.ApplicationBase = path;
                    managerDomain = AppDomain.CreateDomain("Tsanie.Plugins.ManagerDomain", null, ads);

                    // 插件配置文件
                    using (StreamReader reader = new StreamReader(path + Common.CONFIG_NAME))
                    {
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            if (line.Length > 0)
                            {
                                string[] kv = line.Split(',');
                                if (kv.Length != 2)
                                {
                                    continue;
                                }
                                LoadOnePlugin(kv[0], kv[1]);
                            }
                        }
                        reader.Close();
                    }

                    this.BeginInvoke(new Action(delegate
                    {
                        // 选中第一个
                        if (listProviders.Items.Count > 0)
                        {
                            ListViewItem lvi = listProviders.Items[0];
                            lvi.Focused = true;
                            lvi.Selected = true;
                        }
                        buttonAdd.Enabled = true;
                        buttonRemove.Enabled = true;
                        buttonOK.Enabled = true;
                        buttonApply.Enabled = true;
                        listProviders.Enabled = true;
                        MakeEdited(false);
                    }));
                })
                {
                    Name = "thread_LoadPlugins"
                }.Start();
            }
            catch (Exception e)
            {
                Common.OutputError("LoadPlugins()", e);
            }
        }
        void LoadOnePlugin(string assembly, string className)
        {
            try
            {
                bool enabled = true;
                if (assembly.Length > 1 && assembly[0] == '#')
                {
                    assembly = assembly.Substring(1);
                    enabled = false;
                }
                BaseProvider provider = (BaseProvider)managerDomain.CreateInstanceAndUnwrap(assembly, className);
                string[] exts = provider.Exts;
                if (exts == null || exts.Length == 0)
                {
                    Common.OutputDebugString("LoadOnePlugin('{0}', '{1}'):: Exts of '{2}' can't be empty.", assembly, className, provider);
                }
                else
                {
                    this.Invoke(new Action(delegate
                    {
                        AddItem(provider, assembly, className).Checked = enabled;
                    }));
                }
            }
            catch (Exception e)
            {
                Common.OutputError(string.Format("LoadOnePlugin('{0}', '{1}')", assembly, className), e);
            }
        }

        void MakeEdited(bool flag)
        {
            buttonApply.Enabled = flag;
        }
        ListViewItem AddItem(BaseProvider provider, string assembly, string className)
        {
            ListViewItem lvi = new ListViewItem();
            lvi.Text = string.Empty;
            lvi.Tag = provider;
            lvi.SubItems.Add(assembly);
            lvi.SubItems.Add(className);
            lvi.Checked = true;
            switch (provider.Type)
            {
                case ProviderType.Thumbnail:
                    lvi.Group = listProviders.Groups["groupThumbnail"];
                    break;
                case ProviderType.ContextMenu:
                    lvi.Group = listProviders.Groups["groupContextMenu"];
                    break;
                case ProviderType.InfoTip:
                    lvi.Group = listProviders.Groups["groupInfoTip"];
                    break;
                case ProviderType.Icon:
                    lvi.Group = listProviders.Groups["groupIcon"];
                    break;
                case ProviderType.PropertySheet:
                    lvi.Group = listProviders.Groups["groupPropertySheet"];
                    break;
            }
            listProviders.Items.Add(lvi);
            return lvi;
        }
        void ReadInformation(BaseProvider provider, ListViewItem item)
        {
            textProvierName.Text = provider.ProviderName;
            textCreator.Text = provider.Creator;
            textDescription.Text = provider.Description;
            textExts.Text = string.Join(", ", provider.Exts);

            textAssembly.Text = item.SubItems[1].Text;
            textClassName.Text = item.SubItems[2].Text;
        }

        #region - Events -

        void PluginsForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            AppDomain.Unload(managerDomain);
        }
        void PluginsForm_Shown(object sender, EventArgs e)
        {
            Common.SetWindowTheme(listProviders.Handle, "explorer", null);
            LoadPlugins();
        }

        void listProviders_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listProviders.SelectedIndices.Count > 0)
            {
                ListViewItem item = listProviders.SelectedItems[0];
                if (item.Tag == null)
                {
                    textProvierName.Text = null;
                    textCreator.Text = null;
                    textDescription.Text = null;
                    textExts.Text = null;
                    textFlags.Text = null;
                    textAssembly.Text = item.SubItems[1].Text;
                    textClassName.Text = item.SubItems[2].Text;
                }
                else
                {
                    BaseProvider provider = (BaseProvider)item.Tag;
                    try
                    {
                        ReadInformation(provider, item);
                    }
                    catch (RemotingException)
                    {
                        provider = (BaseProvider)managerDomain.CreateInstanceAndUnwrap(item.SubItems[1].Text, item.SubItems[2].Text);
                        ReadInformation(provider, item);
                    }
                    catch (Exception ex)
                    {
                        Common.OutputError("listProviders_SelectedIndexChanged, " + provider, ex);
                    }
                }
            }
        }
        void listProviders_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            MakeEdited(true);
        }

        void buttonAdd_Click(object sender, EventArgs e)
        {
            if (openFile.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
            {
                string ph = openFile.FileName.Substring(openFile.FileName.LastIndexOf('\\') + 1);
                int index = ph.LastIndexOf('.');
                if (index > 0)
                {
                    ListViewItem lvi = AddItem(null, string.Empty, string.Empty);
                    lvi.Text = ph;
                    lvi.Focused = true;
                    lvi.Selected = true;
                    MakeEdited(true);
                    listProviders.Focus();
                }
            }
        }
        void buttonRemove_Click(object sender, EventArgs e)
        {
            if (listProviders.SelectedIndices.Count > 0)
            {
                int index = listProviders.SelectedIndices[0];
                ListViewItem item = listProviders.SelectedItems[0];
                listProviders.Items.Remove(item);
                // 还剩，转移选中项
                if (listProviders.Items.Count > 0)
                {
                    if (index > 0)
                    {
                        index--;
                    }
                    item = listProviders.Items[index];
                    item.Focused = true;
                    item.Selected = true;
                    listProviders.Focus();
                }
            }
        }

        void textAssembly_TextChanged(object sender, EventArgs e)
        {
            if (listProviders.SelectedIndices.Count > 0)
            {
                ListViewItem item = listProviders.SelectedItems[0];
                if (item.SubItems[1].Text != textAssembly.Text)
                {
                    item.SubItems[1].Text = textAssembly.Text;
                    MakeEdited(true);
                }
            }
        }
        void textClassName_TextChanged(object sender, EventArgs e)
        {
            if (listProviders.SelectedIndices.Count > 0)
            {
                ListViewItem item = listProviders.SelectedItems[0];
                if (item.SubItems[2].Text != textClassName.Text)
                {
                    item.SubItems[2].Text = textClassName.Text;
                    MakeEdited(true);
                }
            }
        }

        void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        void buttonOK_Click(object sender, EventArgs e)
        {
            if (buttonApply.Enabled)
            {
                Apply();
            }
            this.Close();
        }
        void buttonApply_Click(object sender, EventArgs e)
        {
            Apply();
            LoadPlugins();
        }

        #endregion

        void Apply()
        {
            // 卸载插件
            Manager.UnloadPlugins();
            // 修改配置文件
            using (StreamWriter writer = new StreamWriter(path + Common.CONFIG_NAME))
            {
                foreach (ListViewItem item in listProviders.Items)
                {
                    if (!item.Checked)
                    {
                        writer.Write('#');
                    }
                    writer.Write(item.SubItems[1].Text);
                    writer.Write(',');
                    writer.WriteLine(item.SubItems[2].Text);
                }
                writer.Flush();
                writer.Close();
            }
            // 重新装载
            Manager.LoadPlugins();
        }
    }

    internal class DoubleBufferedListView : ListView
    {
        public DoubleBufferedListView()
            : base()
        {
            this.SetStyle(
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint, true);
        }
    }
}
